package cn.kgc.vue.service.impl;

import cn.hutool.captcha.LineCaptcha;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.crypto.digest.DigestUtil;
import cn.kgc.vue.commons.Const;
import cn.kgc.vue.commons.QueryCondition;
import cn.kgc.vue.commons.ResponseResult;
import cn.kgc.vue.entity.Permission;
import cn.kgc.vue.entity.RolePers;
import cn.kgc.vue.entity.User;
import cn.kgc.vue.entity.UserRole;
import cn.kgc.vue.form.UserForm;
import cn.kgc.vue.mapper.*;
import cn.kgc.vue.service.UserService;
import cn.kgc.vue.utils.IpUtil;
import cn.kgc.vue.utils.JWTUtil;
import cn.kgc.vue.vo.UserVO;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.crypto.hash.Md5Hash;
import org.springframework.beans.BeanUtils;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @author mengshun
 * @description 针对表【sys_user】的数据库操作Service实现
 * @createDate 2024-06-28 14:17:56
 * <p>
 * 后续为了更加遍历的调试程序  数据的输出信息可以通过日志的形式进行输出
 * 后面可以通过调整日志的级别来控制信息是否输出  不要要改写代码
 * debug < info < warning < error
 * log.debug()
 * log.info()
 * log.warning()
 * log.error()
 */
@Service
@Slf4j
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Resource
    private JWTUtil jwtUtil;

    @Resource
    private DeptMapper deptMapper;

    @Resource
    private UserRoleMapper userRoleMapper;

    @Resource
    private RoleMapper roleMapper;

    @Resource
    private RolePersMapper rolePersMapper;

    @Resource
    private PermissionMapper permissionMapper;

    //  data:image/png;base64,
    //  cookie   ->  session  前后端分离  cookie

    @Override
    public ResponseResult getCaptcha() {
        // 创建验证码对象
        LineCaptcha lineCaptcha = new LineCaptcha(110, 40, 4, 4);
        String code = lineCaptcha.getCode();
        String uuid = IdUtil.simpleUUID();
        // uuid:code
        stringRedisTemplate.opsForValue().set(uuid, code, 3, TimeUnit.MINUTES);
        String image = lineCaptcha.getImageBase64();
        return ResponseResult.success().data("uuid", uuid).data("image", image);
    }

    @Override
    public ResponseResult login(HashMap<String, Object> params, HttpServletRequest request) {

        // 验证码的校验
        String uuid = (String) params.get("uuid");
        String redisCode = stringRedisTemplate.opsForValue().get(uuid);
        if (StringUtils.isBlank(redisCode)) {
            return ResponseResult.fail().message("验证码失效，请刷新重试!!!");
        }

        // 验证码是否正确
        String formCode = (String) params.get("code");
        if (!StringUtils.equals(redisCode, formCode)) {
            return ResponseResult.fail().message("验证码错误");
        }

        //  根据用户名查询用户信息
        String username = (String) params.get("username");
        LambdaQueryWrapper<User> lambda = new QueryWrapper<User>().lambda();
        lambda.eq(User::getUsername, username);
        User user = baseMapper.selectOne(lambda);
        if (ObjectUtils.isNull(user)) {
            return ResponseResult.fail().message("用户名错误");
        }

        // 比较密码
        String formPassword = (String) params.get("password");
        String salt = user.getSalt();
        String formMd5Password = new Md5Hash(formPassword, salt, 10).toHex();
        String DbPassword = user.getPassword();

        if (!StringUtils.equals(formMd5Password, DbPassword)) {
            return ResponseResult.fail().message("密码错误");
        }


        // 检查用户的状态  禁用
        Integer state = user.getState();
        if (state == 0) {
            return ResponseResult.fail().message("账户被禁用,请联系管理员");
        }


        // 校验通过
        HashMap<String, Object> payload = new HashMap<>();
        payload.put("username", user.getUsername());
        payload.put("nickName", user.getNickName());
        payload.put("uid", user.getId());
        String token = jwtUtil.createToken(payload);

        // token ： ip
        String ip = IpUtil.getIp(request);
        String md5HexKey = DigestUtil.md5Hex(token);
        stringRedisTemplate.opsForValue().set(md5HexKey, ip);

        return ResponseResult.success().data("token", token).data("nickName", user.getNickName()).message("认证通过");  //  token
    }

    @Override
    public ResponseResult userPage(QueryCondition<User> queryCondition) {

        // 创建分页对象
        Page<User> userPage = new Page<>(queryCondition.getPage(), queryCondition.getLimit());

        // 获取搜索条件
        User searchParams = queryCondition.getSearchParams();
        String username = searchParams.getUsername();
        Integer deptId = searchParams.getDeptId();
        Integer state = searchParams.getState();

        // 根据搜索条件 构造动态sql
        LambdaQueryWrapper<User> lambda = new QueryWrapper<User>().lambda();
        lambda.like(StringUtils.isNotBlank(username), User::getUsername, username)
                .eq(ObjectUtils.isNotNull(deptId), User::getDeptId, deptId)
                .eq(ObjectUtils.isNotNull(state), User::getState, state)
                .orderByDesc(User::getCreateTime);

        baseMapper.selectPage(userPage, lambda);

        List<User> records = userPage.getRecords();
        long total = userPage.getTotal();

        // List<User> records    List<UserVO>
        List<UserVO> userVOS = records.stream().map(user -> {
            UserVO userVO = new UserVO();
            BeanUtils.copyProperties(user, userVO);

            // 部门名称
            Integer deptId1 = user.getDeptId();
            String deptName = deptMapper.selectById(deptId1).getDeptName();
            userVO.setDeptName(deptName);

            //  根据用户id  查询用户角色信息  uid   user_role   roleId   role
            Integer uid = user.getId();

            LambdaQueryWrapper<UserRole> userRoleLambda = new QueryWrapper<UserRole>().lambda();
            userRoleLambda.eq(UserRole::getUserId, uid);

            List<Integer> rids = userRoleMapper.selectList(userRoleLambda).stream()
                    .map(ur -> ur.getRoleId())
                    .collect(Collectors.toList());

            userVO.setRoleId(rids);

            List<String> roleNames = roleMapper.selectBatchIds(rids).stream()
                    .map(role -> role.getRoleCh())
                    .collect(Collectors.toList());
            userVO.setRoleNames(roleNames);


            return userVO;
        }).collect(Collectors.toList());

        return ResponseResult.success().data("total", total).data("tableData", userVOS);
    }

    @Transactional
    @Override
    public ResponseResult deleteUser(List<Integer> ids) {

        // 判定删除的用户是否包含 admin  3
        boolean contains = ids.contains(3);
        if (contains) {
            return ResponseResult.fail().message("删除的用户包含管理员不能删除");
        }
        // 删除用户表中的用户信息
        baseMapper.deleteBatchIds(ids);
        // 删除用户和角色关联表中的数据
        LambdaQueryWrapper<UserRole> lambda = new QueryWrapper<UserRole>().lambda();
        lambda.in(UserRole::getUserId, ids);
        userRoleMapper.delete(lambda);

        return ResponseResult.success().message("删除成功");
    }

    @Transactional
    @Override
    public ResponseResult addUser(UserForm userForm) {

        log.debug("userForm={}", userForm);

        //  user
        User user = new User();
        BeanUtils.copyProperties(userForm, user);

        // 随机盐  密码
        String salt = RandomUtil.randomString(8);
        String md5Pwd = new Md5Hash("111111", salt, 10).toHex();
        user.setSalt(salt);
        user.setPassword(md5Pwd);

        baseMapper.insert(user);
        Integer uid = user.getId();
        //   uid  roleId   =>UserRole  =>  user_role
        List<Integer> roleId = userForm.getRoleId();

        roleId.forEach(rid -> {
            UserRole userRole = new UserRole();
            userRole.setUserId(uid);
            userRole.setRoleId(rid);
            userRoleMapper.insert(userRole);
        });

        return ResponseResult.success().message("添加成功");
    }

    @Override
    public ResponseResult editUser(UserForm userForm) {

        User user = new User();
        BeanUtils.copyProperties(userForm, user);
        log.debug("user={}", user);

        // 更新用户表   version=1  version = 2
        int line = baseMapper.updateById(user);

        if (line == 1) {
            Integer uid = user.getId();
            // 删除用户所有的角色信息
            LambdaQueryWrapper<UserRole> lambda = new QueryWrapper<UserRole>().lambda();
            lambda.eq(UserRole::getUserId, uid);
            userRoleMapper.delete(lambda);
            // 添加用户角色id   uid    ->   user_role
            List<Integer> roleId = userForm.getRoleId();
            roleId.forEach(rid -> {
                UserRole userRole = new UserRole();
                userRole.setRoleId(rid);
                userRole.setUserId(uid);
                userRoleMapper.insert(userRole);
            });

            return ResponseResult.success().message("编辑成功");
        } else {
            return ResponseResult.fail().message("编辑失败");
        }
    }

    @Override
    public ResponseResult getPersonalInfo(HttpServletRequest request) {

        String token = request.getHeader("authorization");
        Map<String, Object> claims = jwtUtil.getClaims(token);
        Integer uid = (Integer) claims.get("uid");

        LambdaQueryWrapper<User> lambda = new QueryWrapper<User>().lambda();
        lambda.eq(User::getId, uid)
                .select(User::getNickName, User::getSex, User::getTel, User::getCity, User::getId,User::getVersion);
        User user = baseMapper.selectOne(lambda);

        return ResponseResult.success().data("personalInfo", user);
    }

    @Override
    public ResponseResult editPersonalPassword(HttpServletRequest request, HashMap<String, String> params) {

        String authorization = request.getHeader("authorization");
        Integer uid = (Integer) jwtUtil.getClaims(authorization).get("uid");

        LambdaQueryWrapper<User> lambda = new QueryWrapper<User>().lambda();
        lambda.eq(User::getId, uid)
                .select(User::getPassword, User::getSalt, User::getId);

        User user = baseMapper.selectOne(lambda);
        String DBPassword = user.getPassword();
        String salt = user.getSalt();

        // 获取用户输入的表单数据
        String oldPassword = params.get("oldPassword");
        String newPassword = params.get("newPassword");

        // 校验旧密码是否正确
        String md5Password = new Md5Hash(oldPassword, salt, 10).toHex();

        if (!StringUtils.equals(DBPassword, md5Password)) {
            return ResponseResult.fail().message("原始密码不正确");
        }

        // 密码校验通过 加密新密码
        String md5NewPassword = new Md5Hash(newPassword, salt, 10).toHex();
        user.setPassword(md5NewPassword);
        baseMapper.updateById(user);

        // 删除用户的token  用户重新认证
        stringRedisTemplate.delete(DigestUtil.md5Hex(authorization));

        return ResponseResult.success().code(Const.UN_AUTH).message("密码修改成功，请重新登录");
    }

    @Override
    public ResponseResult logout(HttpServletRequest request) {

        String authorization = request.getHeader("authorization");
        stringRedisTemplate.delete(DigestUtil.md5Hex(authorization));
        return ResponseResult.success().message("安全退出");
    }

    @Override
    public ResponseResult userMenu(HttpServletRequest request) {

        //  1. token  uid
        String authorization = request.getHeader("authorization");
        Integer uid = (Integer) jwtUtil.getClaims(authorization).get("uid");

        // 2.根据用户的id  查询用户角色关联表  rid
        LambdaQueryWrapper<UserRole> lambda = new QueryWrapper<UserRole>().lambda();
        lambda.eq(UserRole::getUserId,uid);

        List<Integer> rids = userRoleMapper.selectList(lambda).stream().map(ur -> ur.getRoleId())
                .collect(Collectors.toList());


        // 3. 根据角色id  查询角色权限关联表
        LambdaQueryWrapper<RolePers> rolePersLambda = new QueryWrapper<RolePers>().lambda();
        rolePersLambda.in(RolePers::getRoleId,rids);
        Set<Integer> pids = rolePersMapper.selectList(rolePersLambda).stream()
                .map(rp -> rp.getPerId())
                .collect(Collectors.toSet());


        // 4.查询权限表
        List<Permission> permissions = permissionMapper.selectBatchIds(pids)
                .stream()
                .filter(permission -> permission.getIsMenu() != 2)
                .collect(Collectors.toList());
        return ResponseResult.success().data("menu",permissions);
    }
}




